home *** CD-ROM | disk | FTP | other *** search
- NUMBERS MODULE version 0.08
- ===========================
-
- (C) Copyright Nick Craig-Wood 1992
-
- The module "Numbers" and this documentation "NumModTxt" are public domain.
- You may distribute them freely provided that
- 1) both files are always kept together
- 2) the files are not altered in any way
- 3) no profit is made
- If you wish to break any of these conditions get in touch with me at the
- address below first.
-
- The software and documentation was first published in BBC Acorn User
- Magazine, September 1992, and for more information see that issue.
-
- These routines started life in 1989 written in C on the university mainframe
- in response to a "Numbers Count" puzzle in PCW. The problem (or part of
- it) was to calculate the biggest prime you could find of the form N!+1.
- However the routines did not get finished in time for the puzzle deadline.
- In the quest for speed I converted the routines to 68000 code for my Atari
- ST, and then a year later into ARM code. With an ARM3 the routines run at
- the same speed as they did on the mainframe!
-
- Numbers are held in application memory area in a heap, and maintained by
- OS_Heap. Before the module can be used, it must be told about this
- heap with Num_InitHeap. Numbers come in two pieces, the head and the tail.
- All numbers have a head, but need not have a tail. The head of the number
- is a short block in the heap, which points to the tail and keeps the length
- and sign of the number, and various other things. Numbers are passed by
- reference only, as pointers to the head of the number. These are refered to
- as NUMs. For example NUM r0 indicates that r0 is a pointer to the head of a
- number.
-
- Since NUMs are passed by reference only, if you pass them into procedures
- and then alter the values of the input parameters, you are actually
- altering the NUM. So to avoid problems, if you write a procedure which
- takes NUMs as parameters for both input and output, it is best to define
- some temporary NUMs using Num_Init for the output, and then at the end
- Num_Swap the results into the correct place, and Num_Remove the temporary
- variables. All the internal routines of the module work like this, so there
- is never any problem with passing the same NUM as input and output.
-
- Some of the routines take either NUMs or scalars as arguments. Scalars are
- normal signed or unsigned 32 bit numbers. All routines expect NUMs to be
- tidy (except Num_Tidy). (A num is tidy if its most significant digit is
- non-zero, and if it is zero, then it is positive, and of length 1. Num_Tidy
- accomplishes this. It is unlikely that a user will need this function.)
-
- Any error from the numbers module will be prefixed with "Numbers: ". If you
- pass an invalid NUM to any of the routines, the chances are that OS_Heap
- will reply with an error, but not one that makes sense always. The most
- confusing is "Numbers: Heap Full" so beware! See the end for a short example
- program.
-
- If you find any bugs, have any comments or queries or wish to use the module
- in commercial software please write to
-
- Nick Craig-Wood
- 4 Victoria Street
- Wolverton
- Bucks
- MK12 5HL.
-
- -----------------------------------------------------------------------------
-
- NUMBERS SWI
- ===========
-
- On Entry: r0-r3 are parameters
- On Exit: r0-r3 are returned as results or corrupted
- r4-r14 are preserved
-
- Interrupts: Interrupts are enabled
- Fast interrupts are enabled
-
- Processor mode: Processor is in SVC mode
-
- Re-entrancy: SWIs are not re-entrant
-
- Use: See QUICK REFERENCE, and DEFINITIONS for details
- All SWIs that are capable of looping respond to ESCAPE
- See ERRORS section for details of errors returned
-
- -----------------------------------------------------------------------------
-
- QUICK REFERENCE
- ===============
-
- NUMBERS HEAP: area in application workspace where all the number are kept
- HEAD: 16 byte parameter block in the numbers heap pointing to
- TAIL: variable length block containing the value of the number
- NUM: meaning a 32 bit integer pointing to a HEAD
- INT: meaning a 32 bit integer
- SCALAR: meaning a 32 bit integer
- FLAG: is either 0 for false, or 1 for true
- STRING: a pointer to a 0 terminated ASCII string
-
- a,b,c,d represent pointers to NUMs
- i,j,k represent SCALARS
- p,q represent a pointer to memory
- f represents a FLAG
- h represents a HeapPointer as returned by Num_HeapInit in r0
-
- SWI Parameters Results Comments
- === ========== ======= ========
- Num_Author - - Prints out some info
- Num_InitHeap p,i h,a,b,c h<-HeapPointer, a<-0, b<-1, c<-2
- Num_MakeSmallPrimes i j Makes primes up to i, # found to j
-
- (All the SWIs below need a valid NUM or HeapPointer in r0)
-
- Num_Allocate a,i - Allocates i words to TAIL of a
- Num_Deallocate a - Removes the TAIL of a
- Num_Set a,i - Sets a to signed i
- Num_USet a,i - Sets a to unsigned i
- Num_Init h a Makes a HEAD and TAIL and pointer a
- Num_Remove a - Removes the HEAD and TAIL of a
- Num_Equals a,i f Returns truth of a = i
- Num_Swap a,b - Swaps a and b. This is quick.
- Num_Move a,b - Sets b to a. Not so quick.
- Num_Clear a - Sets TAIL of a to all zeroes
- Num_Tidy a - Reduces a to shortest length
- Num_UCmp a,b i Unsigned compare of a-b to i
- Num_Cmp a,b i Returns the sign of a-b to i
- Num_ScalarCmp a,i j Returns the sign of a-i to j
- Num_ScalarAdd a,i,c - c <- a + i
- Num_ScalarSub a,i,c - c <- a - i
- Num_ScalarMul a,i,c - c <- a * i
- Num_ScalarDiv a,i,c j c <- a / i, j <- a MOD i
- Num_ScalarMod a,i j j <- a MOD i
- Num_SmallFactorN a,i k k=smallest factor of a or 0, try i
- Num_SmallFactor a k k=smallest factor of a or 0, try all
- Num_Add a,b,c - c <- a + b
- Num_Sub a,b,c - c <- a - b
- Num_Mul a,b,c - c <- a * b
- Num_Div a,b,c,d - c <- a / b, d <- a MOD b
- Num_Mod a,b,c - c <- a MOD b
- Num_Dump a - Prints a in hex, and other info
- Num_ToString a p,q Makes STRING of a to p, end=q
- After use do SYS "Num_Deallocate",b
- Num_Print a - Prints a in decimal
- Num_FromString a,p f Converts STRING at p to a, f=ok
- Num_Input a f Gets a decimal input to a, f=ok
- Num_Info h - Prints memory usage info
- Num_RndScalar h i Makes a random number 0-&FFFFFFFF
- Num_SetSeed h,i - Sets seed of rnd generator
- Num_Rnd a,b - Makes random number to a, 0 <= a < b
- Num_Gcd a,b,c - c <- greatest common divisor a,b
- Num_Sqr a,b - b <- square root of a
- Num_Pow a,b,c - c <- a ^ b (a to the power b)
- Num_PowMod a,d,c,b - d <- (a^b) MOD c
- Num_Factorial a,b - b <- a! = a*(a-1)*(a-1)*..*3*2*1
- Num_Inv a,b,c,d - Finds c,d: a*c MOD b=d & d=GCD(a,b)
- Num_FermatTest a,i j Computes truth of i^(a-1) MOD a = 1
- Num_ProbablyPrime a j j <- 0 if not prime, 1 probablyprime
-
- -----------------------------------------------------------------------------
-
- DEFINITIONS
- ===========
-
- Num_InitHeap
- ------------
- This expects r0 as a pointer to a block of memory to be used as a heap, and
- r1 as the length of this memory in bytes. This returns a pointer to the
- heap in r0 and some nums which are useful consants r1 <- zero, r2 <- one, r3
- <- two. The HeapPointer returned in r0 is required by some of the other
- routines.
-
-
- Num_Allocate
- ------------
- This updates NUM r0 to point to a new area of memory of length r1
- (in 32-bit words)
-
-
- Num_Deallocate
- --------------
- This releases the memory used by a NUM (tail), and sets its pointers to NULL
-
-
- Num_Set
- -------
- This sets the NUM supplied in r0 to the signed scalar supplied in r1
-
-
- Num_Uset
- --------
- This sets the NUM supplied in r0 to the unsigned scalar supplied in r1
-
-
- Num_Init
- --------
- Expects r0=HeapPointer
- This returns the address of a new NUM in r0 For creating new or LOCAL
- variables
-
-
- Num_Remove
- ----------
- This removes the allocation for NUM r0 and removes NUM r0 (For removing
- LOCAL variables)
-
-
- Num_Equals
- ----------
- This function returns TRUE in r0 if NUM r0 is equal to the single element
- supplied in r1
-
-
- Num_Swap
- --------
- This swaps the two NUMs in r0 and r1. It is a fast way of getting
- infromation out of temporary variables, before destroying them
-
-
- Num_Move
- --------
- This moves NUM r0 to NUM r1. It does this by actually copying the NUM.
-
-
- Num_Clear
- ---------
- This clears the tail of NUM r0 to all zeros
-
-
- Num_Tidy
- --------
- This makes the NUM r0 use as few digits as possible by removing all the
- leading zeroes
-
-
- Num_UCmp
- --------
- This returns an unsigned comparison between NUM r0 amd NUM r1 in r0 This is
- the SGN(NUM r0 - NUM r1)
-
-
- Num_Cmp
- -------
- This function returns a signed comparison between NUM r0 and NUM r1 It
- returns SGN(NUM r0 - NUM r1)
-
-
- Num_ScalarCmp
- ----------
- This function returns a signed comparison between NUM r0 and SCALAR r1 It
- returns SGN(NUM r0 - NUM r1)
-
-
- Num_ScalarAdd
- ----------
- This adds NUM r0 to (signed int) r1 into NUM r2
-
-
- Num_ScalarSub
- ----------
- This subtracts NUM r0 - (signed int) r1 into NUM r2
-
-
- Num_ScalarDiv
- ----------
- This multiplies NUM r0 by (unsigned int) r1 into NUM r2
-
-
- Num_ScalarMod
- ----------
- This divides NUM r0 by (unsigned int) r1 returning the (unsigned int)
- remainder in r0 int NUM r2
-
-
- Num_Mul
- -------
- NUM r0 * NUM r1 -> NUM r2
-
-
- Num_Div
- -------
- This divides r0 by r1 to give a quotient r2 remainder r3
- For "divide and correct algorithm" see Knuth "Seminumerical Algorthms"
- section 4.3.1
-
-
- Num_Mod
- -------
- This divides r0 by r1 to remainder r2
-
-
- Num_MakeSmallPrimes
- -------------------
- This makes all the primes up to r0, and stores them in the RMA pointed
- to by SmallPrimes. NSmallPrimes is set to the number of primes found.
- It deallocates any old SmallPrimes array so this may be called more than
- once. It returns the number of smallprimes found in r0, and a pointer
- to the array in r1. If there are already more than enough SmallPrimes in
- the RMA then this will not recalculate.
-
-
- Num_Dump
- --------
- This dumps the number supplied in r0 in Hexadecimal, for debugging
-
-
- Num_ToString
- ------------
- This converts the number pointed to by r0 into a decimal string pointed to
- by r0. When finished with, this memory should be released with
- SYS "Num_Heap",3,,r0 It returns the position of the null at the end of the
- num in r1
-
-
- Num_Print
- ---------
- This prints out the number supplied in r0. It prints no spaces or newlines.
-
-
- Num_Info
- --------
- Expects r0=HeapPointer
- This provides information on the numbers module
-
-
- Num_FromString
- --------------
- This converts a number in ASCII base 10 pointed to by r1 into the NUM
- pointed to by r0, until a character which is not 0-9 is reached. If this is
- a control char then true is returned otherwise false is returned deals with
- leading "+","-"," "
-
-
- Num_Input
- ---------
- Inputs a number in base 10 to NUM r0 Returns r0 flagging ok conversion
-
-
- Num_RndScalar
- -------------
- Expects r0=HeapPointer
- Produces a random number into r0 from Seed, and updates it, in the range
- 0-&FFFFFFFF. It works using the algorithm x(n+1)=(1664525 * x(n) +
- 907633393) MOD 2^32 It is known that the least significant bits are not as
- random as the most significant bits, so two consecutive random numbers are
- generated, and combined with EOR after having been rotated by 16 bits with
- respect to each other. This halves the period. Reference; Knuth,
- Seminumerical Algorithms 3.3 p102 p84 This is Line 26, with the best
- spectral co-efficients for a MOD 2^32 generator, listed in Knuth. This form
- is especially easy to calculate with the ARMs mul instruction. The A term is
- calculated as the nearest prime to (1/2-1/3*SQR(3))*2^32.
-
-
- Num_SetSeed
- -----------
- Expects r0=HeapPointer
- This sets the internal 32-bit random number generator to the seed supplied in
- r1
-
-
- Num_Rnd
- -------
- This generates a random number 0 <= rnd < r0 to r1
-
-
- Num_Gcd
- -------
- This finds the gcd(r0,r1) -> r2 using Euclid's algoritm
-
-
- Num_Sqr
- -------
- This takes the square root of r0 to r1 It uses a second order
- Newton-Raphson convergence. This doubles the number of significant figures
- on each iteration. Square root of a negative number if returned as 0. It
- returns the number of iterations in r0
-
-
- Num_Pow
- -------
- This finds r0 to the power of r1 to r2
-
-
- Num_PowMod
- ----------
- This finds r0 to the power of r1 MOD r2 to r3
-
-
- Num_Factorial
- -------------
- This finds NUM r0 factorial to NUM r1 if r0<=1 then r1=0
-
-
- Num_SmallFactorN
- ----------------
- This sees whether NUM r0 has any small factors. It requires
- Num_MakeSmallPrimes to have been called. It tests r1 small primes. It
- returns either the factor found, or 0 to show none found in r0
-
-
- Num_SmallFactor
- ---------------
- This sees whether NUM r0 has any small factors. It requires
- Num_MakeSmallPrimes to have been called. It tests all the small primes
- that have been made. It returns either the factor found, or 0 to show none
- found in r0
-
-
- Num_Inv
- -------
- This finds r2 such that r0*r2 MOD r1=r3 AND r3=GCD(r0,r1) so if GCD(r0,r1)=1
- (for instance if r1 is prime) then this will compute the inverse MOD r1. This
- is adapted from Knuth; Seminumerical Algorithms 4.5.2 pp325
-
-
- Num_FermatTest
- --------------
- This finds whether NUM r0 is a prime with respect to SCALAR r1, using the
- fermat test. That is r0 is not a prime if r1^(r0-1) MOD r0 <> 1 IF
- r1^(r0-1) MOD r0=1 THEN r0 may be a prime. r1 must be prime for the test to
- work. IE this test returns false if r0 is not prime, or true if r0 might be
- prime. This test is less reliable than Num_ProbablyPrime and takes about
- the same time to execute.
-
-
- Num_ProbablyPrime
- -----------------
- This tests whether r0 is prime or not. The function returns (in r0) false
- if the number is not prime, and true if the number is probably prime. The
- algorithm will return true with r0 composite with a probability of less than
- 0.25. This algorithm is as in Knuth - Seminumerical algorithms 4.5.4P
-
- -----------------------------------------------------------------------------
-
- EXAMPLE
- -------
-
- In the spirit of an illustration is worth 1000 words, here is an example
- BASIC program using the numbers module. It tries to find any primes of the
- form 111...111 (these are called rep-units).
-
- REM Check to see we have the numbers module
- *RMEnsure Numbers 0.0 RMLoad Numbers
- *RMEnsure Numbers 0.0 Error 1 Numbers module not found
-
- REM put aside some BASIC memory for the Numbers Heap
- HeapSize=64*1024
- DIM Numbers HeapSize
-
- REM Initialise the Heap
- SYS "Num_HeapInit",Numbers,HeapSize TO hp%,zero%,one%,two%
-
- REM Make some small primes for finding small factors
- SYS "Num_MakeSmallPrimes",5000 TO a%
- PRINT ;a%;" small primes found"
-
- REM This is the number of times we will run Num_ProbablyPrime to be sure
- REM a repunit is prime
- timestotest=20
-
- REM Make the NUM repunit% and start it off at 1
- SYS "Num_Init",hp% TO repunit%
- SYS "Num_Set",repunit%,1
-
- FOR n%=2 TO 100000
- REM repunit=10*repunit+1, ie add 1 digit to the repunit
- SYS "Num_ScalarMul",repunit%,10,repunit%
- SYS "Num_ScalarAdd",repunit%,1,repunit%
-
- PRINT ".";
- REM try to find a small factor of repunit%
- SYS "Num_SmallFactor",repunit% TO composite
- IF composite=0 THEN
- composite=timestotest
- WHILE composite>0
- PRINT "|";
- REM test the primality of repunit% timestotest times
- SYS "Num_ProbablyPrime",repunit% TO pprime
- IF pprime THEN
- composite-=1
- ELSE
- REM if the number is composite but passes a test, this is unusual
- IF composite<>timestotest THEN PRINT "Unusual prime: ";FNprint(repunit%)
- composite=-1
- ENDIF
- ENDWHILE
- ENDIF
- REM print out a prime if we have found one
- IF composite=0 THEN PRINT "R(";n%;") = ";FNprint(repunit%);" is prime"
- NEXT n%
- END
-
- REM This prints NUM a% returning a null string
-
- DEF FNprint(a%): SYS "Num_Print",a%: =""
-
- -----------------------------------------------------------------------------
-
- ERRORS
- ------
-
- The following errors are unique to the Numbers module. However the numbers
- Module will return any OS errors (such as OS_Heap errors) unchanged, except
- for the addition of a prefix of "Numbers: "
-
- Numbers module has become corrupted
- Returned on initialisation if the Numbers code has been changed (say by a
- virus or by a disk error)
-
- Numbers: Unknown Operation
- Returned when an unimplemented numbers SWI is called
-
- Numbers: Escape
- Returned when the user pressed Escape in a Looping SWI.
-
- Numbers: Invalid Heap or NUM
- Returned when HeapPointer is invalid, or an Invalid pointer to a NUM is given
-
- Numbers: Divide by 0 in Num_ScalarDiv
-
- Numbers: Divide by 0 in Num_Div
-
- Numbers: Addback Failed in Num_Div
- This error should never occur. If it does, I would be interested to know!
-
- Numbers: N > NSmallPrimes in Num_SmallFactorN
- Returned when you ask for more SmallPrimes than have been calculated.
-
- -----------------------------------------------------------------------------
-
- REFERENCES
- ==========
-
- Books I have found useful whilst writing this module
-
- "SemiNumerical Algorithms" (2nd Edition) D.E.Knuth, Addison-Wesley
- "Elementary Number Theory" D.M.Burton, Allyn and Bacon
- "Cryptography: an introduction to computer security" J.Seberry, Prentice Hall
-